using System;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Data;
using System.Reflection;
using System.Runtime.InteropServices;
using Fluid.Controls;
using System.Media;
using System.IO;
using LDBUtilities;

namespace Timer
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class TimerTouch : System.Windows.Forms.Form
    {
		private System.Windows.Forms.Label lblStatus;
        private System.Windows.Forms.Timer timer1;

		//default time
		private TimeSpan resetDuration = new TimeSpan(0,0,10);
		//duration when start button is pressed
		private TimeSpan startDuration;
		//current time remaining
		private TimeSpan timeRemaining;
		//time the clock was (re)started
		private DateTime startTime;
		//when true pressing start will remember the time for the reset button
		private bool resetOnStart = false;

		//application full name and path
        private string fullPath = Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
        private System.Windows.Forms.MainMenu mainMenu;
        private System.Windows.Forms.MenuItem miExit;
        private Fluid.Controls.FluidHost fluidHost1;
        FluidButton btnAddHour = new FluidButton("+", 15, 20, 30, 30);
        FluidButton btnAddTenMinutes = new FluidButton("+", 70, 20, 30, 30);
        FluidButton btnAddMinutes = new FluidButton("+", 105, 20, 30, 30);
        FluidButton btnAddTenSeconds = new FluidButton("+", 157, 20, 30, 30);
        FluidButton btnAddSecond = new FluidButton("+", 192, 20, 30, 30);
        FluidButton btnStart = new FluidButton("Start", 15, 225 - 40, 60, 60);
        FluidButton btnStop = new FluidButton("Stop", 90, 225 - 40, 60, 60);
        FluidButton btnReset = new FluidButton("Reset", 162, 225 - 40, 60, 60);
        FluidButton btnSubtractHour = new FluidButton("-", 15, 122, 30, 30);
        FluidButton btnSubtractTenMinutes = new FluidButton("-", 70, 122, 30, 30);
        FluidButton btnSubtractMinute = new FluidButton("-", 105, 122, 30, 30);
        FluidButton btnSubtractTenSeconds = new FluidButton("-", 157, 122, 30, 30);
        FluidButton btnSubtractSecond = new FluidButton("-", 192, 122, 30, 30);
        FluidLabel lblHours = new FluidLabel("0", 10, 60, 40, 50);
        FluidLabel lblColon1 = new FluidLabel(":", 50, 60, 20, 50);
        FluidLabel lblMinutes = new FluidLabel("00", 60, 60, 80, 50);
        FluidLabel lblColon2 = new FluidLabel(":", 140, 60, 20, 50);
        FluidLabel lblSeconds = new FluidLabel("00", 150, 60, 80, 50);

        SoundPlayer soundPlayer;

		private enum State {STOPPED, RUNNING, ALARM};
		private State currentState = State.STOPPED;

		public TimerTouch()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

            //set up touch gui
            fluidHost1.Bounds = fluidHost1.ClientBounds;
            fluidHost1.BackColor = Color.Empty;

            //screen
            FluidPanel screen = new FluidPanel();
            screen.BackColor = Color.FromArgb(50, 50, 50);
            screen.EnableDoubleBuffer = true;
            List<FluidButton> buttons = new List<FluidButton>(20);  //list used to style all buttons in one loop
            List<FluidButton> plusMinusButtons = new List<FluidButton>(20);  //list used to style all buttons in one loop
            List<FluidLabel> timerText = new List<FluidLabel>(20);  //list used to style all elements of timer label in one loop
            
            //+ buttons
            btnAddHour.Click += btnDigitButton_Click;
            btnAddTenMinutes.Click += btnDigitButton_Click;
            btnAddMinutes.Click += btnDigitButton_Click;
            btnAddTenSeconds.Click += btnDigitButton_Click;
            btnAddSecond.Click += btnDigitButton_Click;
            plusMinusButtons.Add(btnAddHour);
            plusMinusButtons.Add(btnAddTenMinutes);
            plusMinusButtons.Add(btnAddMinutes);
            plusMinusButtons.Add(btnAddTenSeconds);
            plusMinusButtons.Add(btnAddSecond);
            
            //- buttons
            btnSubtractHour.Click += btnDigitButton_Click;
            btnSubtractTenMinutes.Click += btnDigitButton_Click;
            btnSubtractMinute.Click += btnDigitButton_Click;
            btnSubtractTenSeconds.Click += btnDigitButton_Click;
            btnSubtractSecond.Click += btnDigitButton_Click;
            plusMinusButtons.Add(btnSubtractHour);
            plusMinusButtons.Add(btnSubtractTenMinutes);
            plusMinusButtons.Add(btnSubtractMinute);
            plusMinusButtons.Add(btnSubtractTenSeconds);
            plusMinusButtons.Add(btnSubtractSecond);

            //control buttons
            btnStart.Click += btnStart_Click;
            btnStop.Click += btnStop_Click;
            btnReset.Click += btnReset_Click;
            buttons.Add(btnStart);
            buttons.Add(btnStop);
            buttons.Add(btnReset);

            timerText.Add(lblHours);
            timerText.Add(lblColon1);
            timerText.Add(lblMinutes);
            timerText.Add(lblColon2);
            timerText.Add(lblSeconds);

            //style all buttons
            foreach (FluidButton b in buttons)
            {
                b.BackColor = Color.Gray;
                b.ForeColor = Color.Black;
                b.Anchor = FluidPanel.AnchorBLR;
                screen.Controls.Add(b);
            }

            //style all plus/minus buttons
            foreach (FluidButton b in plusMinusButtons)
            {
                b.BackColor = Color.DarkGray;
                b.ForeColor = Color.Black;
                b.Anchor = FluidPanel.AnchorBLR;
                screen.Controls.Add(b);
            }

            //style timer
            foreach (FluidLabel lblTime in timerText)
            {
                lblTime.ShadowColor = Color.Black;
                lblTime.ForeColor = Color.White;
                lblTime.Alignment = StringAlignment.Center;
                lblTime.LineAlignment = StringAlignment.Center;
                lblTime.Font = new Font(FontFamily.GenericSansSerif, 40f, FontStyle.Bold);
                screen.Controls.Add(lblTime);
            }

            screen.ShowMaximized();

            soundPlayer = new SoundPlayer(Path.GetDirectoryName(fullPath) + Path.DirectorySeparatorChar + "alarm_3.wav");
            soundPlayer.Load();

			timeRemaining = resetDuration;
			setState(State.STOPPED);
			displayTime();
		}
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			base.Dispose( disposing );
		}
		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TimerTouch));
            this.mainMenu = new System.Windows.Forms.MainMenu();
            this.miExit = new System.Windows.Forms.MenuItem();
            this.lblStatus = new System.Windows.Forms.Label();
            this.timer1 = new System.Windows.Forms.Timer();
            this.fluidHost1 = new Fluid.Controls.FluidHost();
            this.SuspendLayout();
            // 
            // mainMenu
            // 
            this.mainMenu.MenuItems.Add(this.miExit);
            // 
            // miExit
            // 
            this.miExit.Text = "Exit";
            this.miExit.Click += new System.EventHandler(this.miExit_Click);
            // 
            // lblStatus
            // 
            this.lblStatus.Location = new System.Drawing.Point(8, 248);
            this.lblStatus.Name = "lblStatus";
            this.lblStatus.Size = new System.Drawing.Size(232, 20);
            this.lblStatus.Text = "Status";
            this.lblStatus.BackColor = Color.FromArgb(50, 50, 50);
            this.lblStatus.ForeColor = Color.LightGray;
            // 
            // timer1
            // 
            this.timer1.Interval = 1000;
            this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
            // 
            // fluidHost1
            // 
            this.fluidHost1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.fluidHost1.Location = new System.Drawing.Point(0, 0);
            this.fluidHost1.Name = "fluidHost1";
            this.fluidHost1.Size = new System.Drawing.Size(240, 268);
            this.fluidHost1.TabIndex = 19;
            this.fluidHost1.Text = "fluidHost1";
            // 
            // TimerTouch
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
            this.ClientSize = new System.Drawing.Size(240, 268);
            this.Controls.Add(this.lblStatus);
            this.Controls.Add(this.fluidHost1);
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.Menu = this.mainMenu;
            this.Name = "TimerTouch";
            this.Text = "Timer Touch";
            this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>

		static void Main() 
		{
			Application.Run(new TimerTouch());
		}

		/// <summary>
		/// Called by the timer each second. Updates the timeRemaining
		/// </summary>
		/// <param name="stateInfo"></param>
		private void timer1_Tick(object sender, System.EventArgs e)
		{

			switch(currentState) 
			{
				case State.RUNNING:
					timeRemaining = startDuration - (DateTime.Now-startTime);
					//check if alarm should go off
					if( timeRemaining.TotalSeconds <=0 ) 
					{
						timeRemaining = TimeSpan.Zero;
						setState(State.ALARM);
					}
					displayTime();
					break;
				case State.ALARM:
					//play sound as long as alarm is on
                    soundPlayer.Play();
					break;
			}
		
		}

		/// <summary>
		/// Displays the current timer values on screen.
		/// </summary>
		private void displayTime() 
		{
			lblHours.Text = timeRemaining.Hours.ToString();
			lblMinutes.Text = formatTimeUnit(timeRemaining.Minutes);
			lblSeconds.Text = formatTimeUnit(timeRemaining.Seconds);
		}

		/// <summary>
		/// Returns a string of two digits (or more) representing the time provided.
		/// </summary>
		/// <param name="time"></param>
		/// <returns></returns>
		private string formatTimeUnit(int time) 
		{
			if( time < 10 ) 
			{
				return "0"+time;
			}
			else 
			{
				return time.ToString();
			}
		}

		/// <summary>
		/// Must be called for a state change. Sets the timer and gui accordingly.
		/// </summary>
		/// <param name="newState"></param>
		private void setState(State newState) 
		{
			currentState = newState;
			switch(currentState) 
			{
				case State.STOPPED:
					timer1.Enabled = false;
					btnStart.Enabled = true;
					btnStop.Enabled = false;
					btnReset.Enabled = true;
					lblStatus.Text = "";
                    break;
				case State.RUNNING:
					timer1.Enabled = true;
					btnStart.Enabled = false;
					btnStop.Enabled = true;
					btnReset.Enabled = false;
					lblStatus.Text = "";
					break;
				case State.ALARM:
                    DevicePower.SetSystemPowerState(null, DevicePower.POWER_STATE_ON, DevicePower.POWER_FORCE);	//power on if standby
                    //Keyboard.mouse_event();
					BringToFront();
					timer1.Enabled = true;
					btnStart.Enabled = false;
					btnStop.Enabled = true;
					btnReset.Enabled = false;
					lblStatus.Text = "Alarm!";
                    soundPlayer.Play();
					break;
			}
		}

		private void btnStart_Click(object sender, System.EventArgs e)
		{
			if( resetOnStart ) 
			{
				resetOnStart = false;
				resetDuration = timeRemaining;
			}
			startTime = DateTime.Now;
			startDuration = timeRemaining;		//continiue counting if paused
			
			//if more than 15 second until alarm, make sure app wakes up if pda turned off
			if( timeRemaining.TotalSeconds >= 15 ) 
			{
				DateTime wakeupTime = startTime+timeRemaining - new TimeSpan(0, 0, 5); //wake up 5 seconds before alarm
				RunAppAtTime(fullPath, wakeupTime );		//app wakeup
			}
			setState(State.RUNNING);
		}

		private void btnStop_Click(object sender, System.EventArgs e)
		{
			//RunAppAtTime(fullPath, DateTime.MinValue );		//stop app wakeup
			setState(State.STOPPED);
		}

		private void btnReset_Click(object sender, System.EventArgs e)
		{
			timeRemaining = resetDuration;
			displayTime();
		}

		private void miExit_Click(object sender, System.EventArgs e)
		{
			Close();
		}

		private void btnDigitButton_Click(object sender, System.EventArgs e)
		{
			resetOnStart = true;
			int increment = -1;
			bool lastDigit = false;

			//check if add button
			if( sender == btnAddSecond || sender == btnAddTenSeconds || sender == btnAddMinutes || sender == btnAddTenMinutes || sender == btnAddHour)
			{
				increment = 1;				
			}
			//check if last digit
			if( sender == btnAddSecond || sender == btnSubtractSecond || sender == btnAddMinutes || sender == btnSubtractMinute || sender == btnAddHour || sender == btnSubtractHour) 
			{
				lastDigit = true;
			}
			//check if seconds
			if( sender == btnAddSecond || sender == btnSubtractSecond || sender == btnAddTenSeconds || sender == btnSubtractTenSeconds ) 
			{
				timeRemaining = new TimeSpan( timeRemaining.Hours, timeRemaining.Minutes, updateDigit(timeRemaining.Seconds, increment, lastDigit) );
			}
				//check if minutes
			else if ( sender == btnAddMinutes || sender == btnSubtractMinute || sender == btnAddTenMinutes || sender == btnSubtractTenMinutes ) 
			{
				timeRemaining = new TimeSpan( timeRemaining.Hours, updateDigit(timeRemaining.Minutes, increment, lastDigit), timeRemaining.Seconds );
			}
				//check if hours
			else if ( sender == btnAddHour || sender == btnSubtractHour ) 
			{
				timeRemaining = new TimeSpan( updateDigit(timeRemaining.Hours, increment, lastDigit), timeRemaining.Minutes, timeRemaining.Seconds );
			}
			displayTime();
		}

		/// <summary>
		/// Updates a digit (either hour, minute or second) and makes the numbers roll.
		/// </summary>
		/// <param name="digitValue">the value of the digit</param>
		/// <param name="increment">value to add (could be negative)</param>
		/// <param name="lastDigit">true if the last digit should be rolled. If false the high diget is rolled.</param>
		/// <returns></returns>
		private int updateDigit( int digitValue, int increment, bool lastDigit ) 
		{ 
			int lowDigit = digitValue - 10*(digitValue/10);
			int highDigit = digitValue/10;
			if( lastDigit )
			{
				lowDigit = (10 + lowDigit+increment)%10;
			}
			else 
			{
				highDigit = (6 + highDigit+increment)%6;
			}
			return 10*highDigit+lowDigit;
		}


		/// <summary>   
		/// This function prompts the system to start running a specified application at a specified time.   
		/// </summary>   
		/// <param name="appName">Name of the application to be started.</param>   
		/// <param name="time">DateTime at which to run application.</param>
		/// <remarks>To cancel an existing RunAppATime request pass the application name and DateTime.MinValue</remarks>
		public static void RunAppAtTime(string appName, System.DateTime time)   
		{   
			byte[] timebytes;

			if(time==System.DateTime.MinValue)
			{
				//cancel request pass null
				timebytes = null;
			}
			else
			{
				//get native system time struct
				SystemTime st = SystemTime.FromDateTime(time);
				//get bytes
				timebytes = st.ToByteArray();
			}

			if(!DevicePower.CeRunAppAtTime(appName, timebytes))   
			{   
				throw new Exception("Cannot Set Notification Handler");   
			}  
		}   
		






	}
}
